// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package atomic

import (
	"unsafe"
)

// 一个值提供一个原子负载，并存储一个一致类型的值。
// 一个值的零值从Load返回nil。
// 一旦调用了存储，就不能复制值。
// 
// 首次使用后不得复制值。
type Value struct {
	v any
}

// ifaceWords是接口{}的内部表示。
type ifaceWords struct {
	typ  unsafe.Pointer
	data unsafe.Pointer
}

// Load返回最近存储设置的值。
// 如果没有调用存储此值，则返回nil。
func (v *Value) Load() (val any) {
	vp := (*ifaceWords)(unsafe.Pointer(v))
	typ := LoadPointer(&vp.typ)
	if typ == nil || typ == unsafe.Pointer(&firstStoreInProgress) {
		// 第一家商店尚未完工。
		return nil
	}
	data := LoadPointer(&vp.data)
	vlp := (*ifaceWords)(unsafe.Pointer(&val))
	vlp.typ = typ
	vlp.data = data
	return
}

var firstStoreInProgress byte

// Store将值的值设置为x。
// 对给定值的所有存储调用都必须使用相同具体类型的值。
// 不一致类型的存储会出现恐慌，存储也会出现恐慌（nil）。
func (v *Value) Store(val any) {
	if val == nil {
		panic("sync/atomic: store of nil value into Value")
	}
	vp := (*ifaceWords)(unsafe.Pointer(v))
	vlp := (*ifaceWords)(unsafe.Pointer(&val))
	for {
		typ := LoadPointer(&vp.typ)
		if typ == nil {
			// 尝试启动第一家门店。
			// 禁用抢占，以便其他Goroutine可以使用
			// 活动自旋等待等待完成。
			runtime_procPin()
			if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(&firstStoreInProgress)) {
				runtime_procUnpin()
				continue
			}
			// 完成第一个存储。
			StorePointer(&vp.data, vlp.data)
			StorePointer(&vp.typ, vlp.typ)
			runtime_procUnpin()
			return
		}
		if typ == unsafe.Pointer(&firstStoreInProgress) {
			// 第一家门店正在建设中。等待
			// 由于我们在第一个存储区周围禁用了抢占，
			// 我们可以使用主动旋转等待。
			continue
		}
		// 第一家店铺完工。检查类型并覆盖数据。
		if typ != vlp.typ {
			panic("sync/atomic: store of inconsistently typed value into Value")
		}
		StorePointer(&vp.data, vlp.data)
		return
	}
}

// Swap将新值存储为值，并返回以前的值。如果
// 该值为空，则返回nil。
// 
// 所有交换给定值的调用必须使用相同具体
// 类型的值。不一致类型的掉期恐慌，掉期（零）也是如此。
func (v *Value) Swap(new any) (old any) {
	if new == nil {
		panic("sync/atomic: swap of nil value into Value")
	}
	vp := (*ifaceWords)(unsafe.Pointer(v))
	np := (*ifaceWords)(unsafe.Pointer(&new))
	for {
		typ := LoadPointer(&vp.typ)
		if typ == nil {
			// 尝试启动第一家店铺。
			// 禁用抢占，以便其他Goroutine可以使用
			// 活动自旋等待等待完成；这样
			// GC就不会意外地看到假类型。
			runtime_procPin()
			if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) {
				runtime_procUnpin()
				continue
			}
			// 完成第一家门店。
			StorePointer(&vp.data, np.data)
			StorePointer(&vp.typ, np.typ)
			runtime_procUnpin()
			return nil
		}
		if uintptr(typ) == ^uintptr(0) {
			// 第一家门店正在建设中。等待
			// 由于我们在第一家商店周围禁用了抢占，
			// 我们可以使用主动旋转等待。
			continue
		}
		// 第一家店铺完工。检查类型并覆盖数据。
		if typ != np.typ {
			panic("sync/atomic: swap of inconsistently typed value into Value")
		}
		op := (*ifaceWords)(unsafe.Pointer(&old))
		op.typ, op.data = np.typ, SwapPointer(&vp.data, np.data)
		return old
	}
}

// CompareAndSwap对值执行比较和交换操作。
// 
// 所有对给定值的CompareAndSwap调用必须使用相同
// 具体类型的值。不一致类型的CompareAndSwap恐慌，
// CompareAndSwap（old，nil）也是如此。
func (v *Value) CompareAndSwap(old, new any) (swapped bool) {
	if new == nil {
		panic("sync/atomic: compare and swap of nil value into Value")
	}
	vp := (*ifaceWords)(unsafe.Pointer(v))
	np := (*ifaceWords)(unsafe.Pointer(&new))
	op := (*ifaceWords)(unsafe.Pointer(&old))
	if op.typ != nil && np.typ != op.typ {
		panic("sync/atomic: compare and swap of inconsistently typed values")
	}
	for {
		typ := LoadPointer(&vp.typ)
		if typ == nil {
			if old != nil {
				return false
			}
			// 尝试开设第一家门店。
			// 禁用抢占，以便其他Goroutine可以使用
			// 活动自旋等待等待完成；这样
			// GC就不会意外地看到假类型。
			runtime_procPin()
			if !CompareAndSwapPointer(&vp.typ, nil, unsafe.Pointer(^uintptr(0))) {
				runtime_procUnpin()
				continue
			}
			// 完成第一家门店。
			StorePointer(&vp.data, np.data)
			StorePointer(&vp.typ, np.typ)
			runtime_procUnpin()
			return true
		}
		if uintptr(typ) == ^uintptr(0) {
			// 第一家门店正在进行中。等待
			// 由于我们在第一家商店周围禁用了抢占，
			// 我们可以使用主动旋转等待。
			continue
		}
		// 第一家店铺完工。检查类型并覆盖数据。
		if typ != np.typ {
			panic("sync/atomic: compare and swap of inconsistently typed value into Value")
		}
		// 通过运行时相等性检查比较旧版本和当前版本。
		// 这允许比较值类型，这是包函数不提供的。
		// 下面的比较WAPPointer仅确保vp。数据
		// 自LoadPointer之后未更改。
		data := LoadPointer(&vp.data)
		var i any
		(*ifaceWords)(unsafe.Pointer(&i)).typ = typ
		(*ifaceWords)(unsafe.Pointer(&i)).data = data
		if i != old {
			return false
		}
		return CompareAndSwapPointer(&vp.data, data, np.data)
	}
}

// 禁用/启用抢占，在运行时实现。
func runtime_procPin()
func runtime_procUnpin()
